#include "gd32h7xx.h"
#include "systick.h"
#include <stdio.h>
#include <math.h>

/* 测试参数配置（适配512KB RAM） */
#define TEST_SIZE 5000        // 数组大小
#define TEST_REPEAT 200       // 重复次数
#define PEAK_TEST_COUNT 50000000  // 峰值测试运算次数

/* 静态数组减少栈内存占用 */
static float f_a[TEST_SIZE], f_b[TEST_SIZE], f_c[TEST_SIZE];
static double d_a[TEST_SIZE], d_b[TEST_SIZE], d_c[TEST_SIZE];

/*!
    \brief      使能CPU缓存（带同步屏障）
*/
static void cache_enable(void)
{
    SCB_EnableICache();
    __DSB();
    __ISB();

    SCB_EnableDCache();
    __DSB();
    __ISB();
}

/*!
    \brief      初始化USART0（PA9-TX, PA10-RX）
*/
void usart_init(void)
{
    rcu_periph_clock_enable(RCU_USART0);
    rcu_periph_clock_enable(RCU_GPIOA);
    
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9 | GPIO_PIN_10);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9 | GPIO_PIN_10);
    
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
}

/*!
    \brief      阻塞发送单个字符
*/
void usart_send_char(uint8_t ch)
{
    usart_data_transmit(USART0, ch);
    while(usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
}

/*!
    \brief      重定向printf到USART
*/
int fputc(int ch, FILE *f)
{
    usart_send_char((uint8_t)ch);
    return ch;
}

/*!
    \brief      初始化测试数据
*/
void init_test_data(void)
{
    for (int i = 0; i < TEST_SIZE; i++) {
        f_a[i] = (float)(i * 123 % 997) / 3.1415926f;
        f_b[i] = (float)(i * 457 % 883) / 2.7182818f;
        d_a[i] = (double)(i * 313 % 769) / 3.1415926535;
        d_b[i] = (double)(i * 541 % 673) / 2.7182818284;
    }
}

/*!
    \brief      精确计时函数（返回微秒数，纯寄存器操作）
*/
uint32_t get_ticks_us(void)
{
    static uint32_t overflow_count = 0;  // 溢出次数计数
    static uint32_t last_val = 0;        // 上一次计数值
    
    uint32_t current_val = SysTick->VAL;  // 当前计数值（递减）
    
    // 检测SysTick溢出（当前值 > 上次值，说明溢出一次）
    if (current_val > last_val) {
        overflow_count++;
    }
    last_val = current_val;
    
    // 计算总微秒数：
    // SysTick时钟 = HCLK/8 = 400MHz/8 = 50MHz → 周期20ns
    // 总计数 = 溢出次数×最大计数值 + (最大计数值 - 当前值)
    uint32_t total_ticks = overflow_count * SysTick->LOAD + (SysTick->LOAD - current_val);
    return (total_ticks * 20) / 1000;  // 转换为微秒（20ns/tick → 1tick=0.02us → ×20/1000）
}

/*!
    \brief      测试单精度浮点运算性能
*/
float test_single_precision(void)
{
    uint32_t start_us, end_us;
    uint32_t total_us;
    
    start_us = get_ticks_us();
    
    for (int r = 0; r < TEST_REPEAT; r++) {
        for (int i = 0; i < TEST_SIZE; i++) {
            f_c[i] = f_a[i] * f_b[i] + f_a[i] / (f_b[i] + 1.0f);
            f_c[i] += sqrtf(f_a[i] + 100.0f);
        }
    }
    
    end_us = get_ticks_us();
    total_us = end_us - start_us;
    if (total_us == 0) total_us = 1;
    
    float operations = (float)TEST_SIZE * TEST_REPEAT * 4.0f;
    return operations / (total_us * 1e-6f) / 1e9f;
}

/*!
    \brief      测试双精度浮点运算性能
*/
float test_double_precision(void)
{
    uint32_t start_us, end_us;
    uint32_t total_us;
    
    start_us = get_ticks_us();
    
    for (int r = 0; r < TEST_REPEAT; r++) {
        for (int i = 0; i < TEST_SIZE; i++) {
            d_c[i] = d_a[i] * d_b[i] + d_a[i] / (d_b[i] + 1.0);
            d_c[i] += sqrt(d_a[i] + 100.0);
        }
    }
    
    end_us = get_ticks_us();
    total_us = end_us - start_us;
    if (total_us == 0) total_us = 1;
    
    float operations = (float)TEST_SIZE * TEST_REPEAT * 4.0f;
    return operations / (total_us * 1e-6f) / 1e9f;
}

/*!
    \brief      测试FPU峰值性能
*/
float test_single_peak(void)
{
    uint32_t start_us, end_us;
    uint32_t total_us;
    float a = 123.456f, b = 789.012f, c = 0.0f;
    
    start_us = get_ticks_us();
    
    for (int r = 0; r < PEAK_TEST_COUNT; r++) {
        c = a * b;
        (void)c;
    }
    
    end_us = get_ticks_us();
    total_us = end_us - start_us;
    if (total_us == 0) total_us = 1;
    
    float operations = (float)PEAK_TEST_COUNT;
    return operations / (total_us * 1e-6f) / 1e9f;
}

/*!
    \brief      初始化LED指示灯
*/
void led_init(void)
{
    rcu_periph_clock_enable(RCU_GPIOF);
    rcu_periph_clock_enable(RCU_GPIOA);
    
    gpio_mode_set(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10);
    gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
    
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
    
    gpio_bit_reset(GPIOF, GPIO_PIN_10);
    gpio_bit_reset(GPIOA, GPIO_PIN_6);
}

/*!
    \brief      main函数
*/
int main(void)
{
    float sp_perf, dp_perf, peak_perf;
    
    cache_enable();
    systick_config();  // 配置SysTick（默认HCLK/8，50MHz）
    led_init();
    usart_init();
    
    // 测试开始指示
    gpio_bit_set(GPIOF, GPIO_PIN_10);
    gpio_bit_set(GPIOA, GPIO_PIN_6);
    delay_1ms(1000);  // 使用库自带的毫秒延时
    
    // 打印测试信息
    printf("\n=========================================\n");
    printf("GD32H759I-EVAL评估板 FPU性能测试\n");
    printf("=========================================\n");
    printf("测试数据量: %d, 重复次数: %d\n", TEST_SIZE, TEST_REPEAT);
    printf("初始化测试数据中...\n");
    
    init_test_data();
    printf("数据初始化完成。\n");
    
    // 单精度测试
    gpio_bit_reset(GPIOA, GPIO_PIN_6);
    printf("\n正在运行单精度浮点测试...\n");
    sp_perf = test_single_precision();
    printf("单精度浮点测试完成。\n");
    
    // 双精度测试
    gpio_bit_set(GPIOA, GPIO_PIN_6);
    gpio_bit_reset(GPIOF, GPIO_PIN_10);
    printf("正在运行双精度浮点测试...\n");
    dp_perf = test_double_precision();
    printf("双精度浮点测试完成。\n");
    
    // 峰值性能测试
    gpio_bit_set(GPIOF, GPIO_PIN_10);
    printf("正在运行峰值性能测试...\n");
    peak_perf = test_single_peak();
    printf("峰值性能测试完成。\n");
    
    // 打印结果
    printf("\n=========================================\n");
    printf("测试结果:\n");
    printf("1. 单精度浮点性能: %.2f GFLOPS\n", sp_perf);//单位GFLOPS:每秒执行多少十亿次浮点运算
    printf("2. 双精度浮点性能: %.2f GFLOPS\n", dp_perf);
    printf("3. 峰值性能: %.2f GFLOPS\n", peak_perf);
    printf("=========================================\n");
    printf("测试完成！\n");
    
    // 测试完成，LED闪烁
    gpio_bit_reset(GPIOF, GPIO_PIN_10);
    gpio_bit_reset(GPIOA, GPIO_PIN_6);
    delay_1ms(500);
    while(1) {
        gpio_bit_toggle(GPIOF, GPIO_PIN_10);
        gpio_bit_toggle(GPIOA, GPIO_PIN_6);
        delay_1ms(300);
    }
}